package vip.liux.backend.infrastructure.jpa.product;

import jakarta.persistence.criteria.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import vip.liux.contracts.models.product.Product;
import vip.liux.contracts.repositories.product.ProductRepository;
import vip.liux.contracts.shared.enums.Status;

import java.util.ArrayList;
import java.util.List;

public interface ProductJpaRepository extends JpaRepository<Product, Long>, ProductRepository, JpaSpecificationExecutor<Product> {

    @Override
    default Page<Product> findByCatNo(String catNo, Pageable page) {
        return findAll((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.isNotBlank(catNo)) {
                predicates.add(criteriaBuilder.or(
                        criteriaBuilder.equal(root.get("catNo"), catNo),
                        criteriaBuilder.equal(root.get("catRootNo"), catNo),
                        criteriaBuilder.equal(root.get("catParentNo"), catNo)
                ));
            }
            return query.where(predicates.toArray(new Predicate[0])).getRestriction();
        }, page);
    }

    @Override
    default Page<Product> findAll(String productName, String spu, String catNo, String brandNo, Status status, Pageable page) {
        return findAll((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.isNotBlank(productName)) {
                predicates.add(criteriaBuilder.like(root.get("productName"), "%" + productName + "%"));
            }
            if (StringUtils.isNotBlank(spu)) {
                predicates.add(criteriaBuilder.like(root.get("spu"), "%" + spu + "%"));
            }
            if (StringUtils.isNotBlank(catNo)) {
                predicates.add(criteriaBuilder.or(
                        criteriaBuilder.equal(root.get("catNo"), catNo),
                        criteriaBuilder.equal(root.get("catRootNo"), catNo),
                        criteriaBuilder.equal(root.get("catParentNo"), catNo)
                ));
            }
            if (StringUtils.isNotBlank(brandNo)) {
                predicates.add(criteriaBuilder.equal(root.get("brandNo"), brandNo));
            }
            if (status != null) {
                predicates.add(criteriaBuilder.equal(root.get("status"), status));
            }

            return query.where(predicates.toArray(new Predicate[0])).getRestriction();
        }, page);
    }

    @Transactional
    @Modifying
    @Query("update Product p set p.status = :status where p.spu in :spuList")
    int updateStatusBySpuIn(@Param("spuList") List<String> spuList, @Param("status") Status status);
}